package no.cicero.testframework.reporting;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

public class Reporting {

	static interface Message<T> {
		public void send(T obj) throws Exception;
	}

	static interface MessageNoThrow<T> {
		public void send(T obj);
	}

	static <T> void sendMessage(Collection<T> recipients, Message<T> message) throws Exception{
		for(T recipient: recipients)
			message.send(recipient);
	}

	static <T> void sendMessageNoThrow(Collection<T> recipients, MessageNoThrow<T> message){
		for(T recipient: recipients)
			message.send(recipient);
	}

    private Collection<IReport> reports = new ArrayList<IReport>();
    private ReportingUseCase currentUseCase = null;

    private int failedStepsCount = 0;
    private int totalStepsCount = 0;

	public Reporting() {
	}

    public Reporting(IReport report) {
        addReport(report);
    }    
    
    public Reporting(Collection<IReport> reports) {
        this.reports = reports;
    }

    public Collection<IReport> getReports() { return reports; }
	public void addReport(IReport report){
		reports.add(report);
	}
    public int getTotalStepsCount() { return totalStepsCount; }
    public int getFailedStepsCount() { return failedStepsCount; }
    public ReportingUseCase getCurrentUseCase() { return currentUseCase; }

	public void reportStarted() throws Exception{
		failedStepsCount = 0;
		totalStepsCount = 0;
		currentUseCase = null;
		final Reporting reporting = this;
		notifyReports(new Message<IReport>() {
			public void send(IReport obj) throws IOException {
				obj.reportStarted(reporting);
			}
		});
	}

	public void reportFinished(){
		notifyReportsNoThrow(new MessageNoThrow<IReport>() {
			public void send(IReport obj) {
				obj.reportFinished();
			}
		});
	}


    /**
     * This section implements all methods needed to work 
     * with Use Cases
     */ 
         
    public ReportingUseCase useCaseStart(String useCaseName, String useCaseDescription, String useCaseShortDescription ) {
        currentUseCase = new ReportingUseCase(useCaseName, useCaseDescription, useCaseShortDescription, this);

		notifyReportsNoThrow(new MessageNoThrow<IReport>() {
			public void send(IReport obj) {
				obj.useCaseStarted(currentUseCase);
			}
		});
        return currentUseCase;
    }

    public void useCaseSucceed() {
		notifyReportsNoThrow(new MessageNoThrow<IReport>() {
			public void send(IReport obj) {
				obj.useCaseSucceeded(currentUseCase);
			}
		});
        useCaseEnd();
    }

    public void useCaseFailed(final Exception ex) {
		notifyReportsNoThrow(new MessageNoThrow<IReport>() {
			public void send(IReport obj) {
				obj.useCaseFailed(currentUseCase, ex);
			}
		});
        useCaseEnd();
    }

	void notifyReports(Message<IReport> message) throws Exception{
		sendMessage(reports, message);
	}

	void notifyReportsNoThrow(MessageNoThrow<IReport> message){
		sendMessageNoThrow(reports, message);
	}

    private void useCaseEnd(){
        totalStepsCount  += currentUseCase.getTotalStepsCount();
        failedStepsCount += currentUseCase.getFailedStepsCount();
        currentUseCase = null;
    }
}
